﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AutoHibernate.API;

namespace AutoHibernate.UI
{
    /// <summary>
    /// This is the main WinForm to provide the user interface for the application.
    /// The form also contains most of the logic. Ideally, the logic should be seperated
    /// but I have left it in here for this simple little app.
    /// </summary>
    public partial class MainForm : Form
    {
        private ITimerAction TimerAction { get; set; }
        private ITimeConversion TimeConversion { get; set; }

        public MainForm(ITimerAction timerAction, ITimeConversion timeConversion)
        {
            this.TimerAction = timerAction;
            this.TimeConversion = timeConversion;

            InitializeComponent();  // this method is generated by the Visual Studio tool.
            RegisterEventHandlers();
            ResetGUI();
        }

        /// <summary>
        /// Registers various event handlers for the UI components and timers.
        /// </summary>
        private void RegisterEventHandlers()
        {
            radioOptionAfter.CheckedChanged += new EventHandler(radioOption_CheckedChanged);
            radioOptionAt.CheckedChanged += new EventHandler(radioOption_CheckedChanged);

            btnStart.Click += new EventHandler(btnStart_Click);
            btnStopAndReset.Click += new EventHandler(btnStopAndReset_Click);

            timer.Tick += new EventHandler(timer_Tick);
        }

        /// <summary>
        /// Resets the Graphical User Interface backs to its default state.
        /// </summary>
        private void ResetGUI()
        {
            txtHibernateAfter.Text = "100";
            cmbHibernateAfterUnit.SelectedItem = "" + TimeUnit.Minutes;
            hibernateAtPicker.Value = DateTime.Now.AddMinutes(100);
            radioOptionAfter.Checked = true;
            SelectHibernateAfter();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (ValidateUserInput())
            {
                timer.Interval = CalculateTimeToHibernateInMilliSeconds();
                timer.Start();

                btnStart.Enabled = false;
            }
        }

        private void btnStopAndReset_Click(object sender, EventArgs e)
        {
            timer.Stop();
            btnStart.Enabled = true;
            ResetGUI();
        }

        /// <summary>
        /// This method gets called after the interval of the main timer.
        /// This method calls the PerformAction method of the TimerAction.
        /// To ensure the TimerAction is performed only once, the timer is stopped first
        /// before performing the action.
        /// </summary>
        private void timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();
            try
            {
                TimerAction.PerformAction();
            }
            catch
            {
                MessageBox.Show("Error while performing the timer action");
            }
        }

        /// <summary>
        /// Displays a message to the user.
        /// </summary>
        /// <param name="message">The literal message to be displayed.</param>
        private void ShowMessage(string message)
        {
            MessageBox.Show(message);
        }

        /// <summary>
        /// Validates the user input and shows appropriate error messages when invalid values are entered by the user.
        /// </summary>
        /// <returns>True if the input was valid. False otherwise.</returns>
        /// <see cref="ShowMessage(message)"/>
        private bool ValidateUserInput()
        {
            if (radioOptionAfter.Checked)
            {
                double parsedValue;
                bool parseSuccess = double.TryParse(txtHibernateAfter.Text, out parsedValue);
                if (parseSuccess)
                {
                    if (parsedValue <= 0)
                    {
                        ShowMessage("Please enter a positive number in the text-field.");
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    ShowMessage("You have entered an invalid number. Please enter a valid numeric value in the text-field.");
                    return false;
                }
            }
            else if (radioOptionAt.Checked)
            {
                long remainingTime = hibernateAtPicker.Value.Ticks - DateTime.Now.Ticks;
                if (remainingTime <= 0)
                {
                    ShowMessage("Please select a valid future time in the picker.");
                    return false;
                }
                return true;
            }
            else
            {
                ShowMessage("An invalid option was selected. Please select on of the valid radio buttons.");
                return false;
            }
        }

        private int CalculateTimeToHibernateInMilliSeconds()
        {
            if (radioOptionAfter.Checked)
            {
                string selectedUnit = cmbHibernateAfterUnit.SelectedItem as string;
                switch (selectedUnit)
                {
                    case "Hours":
                        return TimeConversion.ConvertToMilliSeconds(txtHibernateAfter.Text, TimeUnit.Hours);
                    case "Minutes":
                        return TimeConversion.ConvertToMilliSeconds(txtHibernateAfter.Text, TimeUnit.Minutes);
                    case "Seconds":
                        return TimeConversion.ConvertToMilliSeconds(txtHibernateAfter.Text, TimeUnit.Seconds);
                    default:
                        throw new Exception("None of the known time units were selected. This should never be reached.");
                }
            }
            else if (radioOptionAt.Checked)
            {
                return TimeConversion.CalculateAbsoluteDifferenceInMilliSeconds(hibernateAtPicker.Value, DateTime.Now);
            }
            else
            {
                throw new Exception("This should never be executed.");
            }
        }

        void radioOption_CheckedChanged(object sender, EventArgs e)
        {
            if (radioOptionAt.Checked)
            {
                SelectHibernateAt();
            }
            else if (radioOptionAfter.Checked)
            {
                SelectHibernateAfter();
            }
        }

        #region UI Changes when selecting different options
        private void SelectHibernateAfter()
        {
            radioOptionAfter.Checked = true;
            SetHibernateAtOption(false);
            SetHibernateAfterOption(true);            
        }

        private void SelectHibernateAt()
        {
            SetHibernateAtOption(true);
            SetHibernateAfterOption(false);
        }

        private void SetHibernateAtOption(bool enable)
        {
            hibernateAtPicker.Enabled = enable;
        }

        private void SetHibernateAfterOption(bool enable)
        {
            txtHibernateAfter.Enabled = enable;
            cmbHibernateAfterUnit.Enabled = enable;
        }
        #endregion
    }
}
